//
//  Singleton.swift
//  swiftStudy
//
//  Created by unisedu on 16/4/1.
//  Copyright © 2016年 CaoFei. All rights reserved.
//

import UIKit
//不安全单利实现
/*
这段代码的实现，在shared中进行条件判断，如果Inner.instance.为空就生成一个实例，这段代码很简单看出当线程同时访问SwiftSingleton.shared方法时，会有如下问题出现，线程A判断Inner.instance为空，进入if语句后立即切换到线程B执行，线程B也进行判断，由于线程A只是进入了if语句，这行代码
?
1
Inner.instance = SwiftSingleton()

并没有执行，这时Inner.instance还是为空，线程B也进行了if语句，这种情况下就会创建多个实例，没有保证实例的唯一性。上面的理论分析基本上任何一篇文章都会讲的，也不能理解，关键问题，如何测试上面的理论是否正确呢？
*/

class SwiftSingleton {
    var tag:Int = 1
    class var shared: SwiftSingleton {
        if (Inner.instance == nil) {
            Inner.instance = SwiftSingleton()
        }
        return Inner.instance!
    }
    
    struct Inner {
        static var instance: SwiftSingleton?
    }
}

/*
线程抢占原理
其实要实现上面的例子不是很难，创建N个线程，让他同时访问SwiftSingleton.shared的方法，然后将所返回值保存最后比较引用。原理很正确，但是创建线程的过程也是极为耗时的，现在的电脑执行速度又非常快，模拟具有不稳定性。如何才能最大的程序测试上面的安全性呢？这里我们可以考虑一个现实的问题，假设找1000人通过一段100米的赛道，我们想要更多的人同时去冲刺终点，越多越好。如果你找一个人，告诉他去跑100米，然后再找一下，这种肯定同时到达终点的几率很底。怎么办才能让更多的人在同一时刻到达终点呢？问题很简单，让这1000人有一个同一起跑点，让他们都准备好了，随着一声令下，一起奔跑。回到技术问题，我们想要更多的线程访问SwiftSingleton.shared方法，只要先准备好所有的线程，然后发一个信号，让他们同时去访问这个方法就可以了。
*/

//class SwiftSingletonTest: XCTestCase {
//    let condition = NSCondition()
//    let mainCondition = NSCondition()
//    let singleton: NSMutableArray = NSMutableArray()
//    let threadNumbers = 1000
//    var count = 0
//
//
//    func testSingletonThreadSafe() {
//
//        for index in 0...threadNumbers {
//            NSThread.detachNewThreadSelector("startNewThread", toTarget: self, withObject: nil)
//        }
//        condition.broadcast()
//        mainCondition.lock()
//        mainCondition.wait()
//        mainCondition.unlock()
//        checkOnlyOne()
//    }
//
//    func startNewThread() {
//        condition.lock()
//        condition.wait()
//        condition.unlock()
//        let temp = SwiftSingleton.shared
//        count++
//        singleton.addObject(temp)
//        if count >= threadNumbers {
//            mainCondition.signal()
//        }
//    }
//
//    func checkOnlyOne () {
//        let one = singleton[0] as SwiftSingleton
//        for temp : AnyObject  in singleton {
//            let newTemp = temp as SwiftSingleton
//            if(newTemp !== one) {
//                XCTFail("singleton error!");
//                break;
//            }
//        }
//    }
//
//}

/*
这段代码主要使用了NSCondition进行同步，其中NSCondition分为两组，condition主要负责除主线程外的线程，在for语句中会创建并启动N（threadNumbers）个线程，每个线程启动后都会去执行startNewThread方法，执行到语句
?
1
condition.wait()

会挂起当前线程，当所有线程都创建并启动完时，主线程会执行
?
1
condition.broadcast()

来通知挂起的N个线程继承执行，此时主线程调了
?
1
mainCondition.wait()

主线和进入持起状态，此处将主线程挂起是为了在所有线程执行完，依次检查取得引用的唯一性。
?
1
2
3
if count >= threadNumbers {
mainCondition.signal()
}


这种单例并不能保证唯一性
*/
//1、最简单实现

class SwiftSingleton1 {
    
    var tag:Int = 1
    class var shared: SwiftSingleton1 {
        return Inner.instance1
    }
    
    struct Inner {
        static let instance1: SwiftSingleton1 = SwiftSingleton1()
    }
}

/*
解释：上述代表也实现了延迟加载技术
?
1
static let instance: SwiftSingleton = SwiftSingleton()

首次访问Inner.instance时才会创建SwiftSingleton,此处的延迟加载由Swift语言原生提供
*/


//2、使用GCD技术实现的单例模式

class SwiftSingleton2 {
    class var shared: SwiftSingleton2 {
        dispatch_once(&Inner.token) {
            Inner.instance = SwiftSingleton2()
        }
        return Inner.instance!
    }
    struct Inner {
        static var instance: SwiftSingleton2?
        static var token: dispatch_once_t = 0
    }
    
}


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////下边才是正确定////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//class版单利
class SwiftSingleton3{
    
    var tag :Int?
    
    class func shareInstance()->SwiftSingleton3{
        struct YRSingleton{
            static var predicate:dispatch_once_t = 0
            static var instance:SwiftSingleton3? = nil
        }
        dispatch_once(&YRSingleton.predicate,{
            YRSingleton.instance=SwiftSingleton3()
            }
        )
        return YRSingleton.instance!
    }
}

//struct版单利
struct StructSingleton{
    static func shareInstance()->StructSingleton{
        struct YRSingleton{
            static var predicate:dispatch_once_t = 0
            static var instance:StructSingleton? = nil
        }
        dispatch_once(&YRSingleton.predicate,{
            YRSingleton.instance=StructSingleton()
            }
        )
        return YRSingleton.instance!
    }
}

class Singleton: NSObject {
    func show(){
        
        var swiftInstance1=SwiftSingleton3.shareInstance()
        swiftInstance1.tag=3
        var swiftInstance2=SwiftSingleton3.shareInstance()
        print("asdf=====\(swiftInstance2.tag)")
        if swiftInstance1===swiftInstance2{//“===”判别是否是同一个实例对象
            print("they are the same instance!")
        //Swift之GCD开线程通用模版
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
            
            //这里写需要大量时间的代码
            
            dispatch_async(dispatch_get_main_queue(), {
                
                //这里返回主线程，写需要主线程执行的代码
                
            })
            
        })

    }
}



}